﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Windows.Threading;
using Communication = Wormhole.Engine.Communication;

namespace Wormhole.UI.Application.Dialogs.JoinGame
{
	/// <author>Hannes Foulds</author>
	/// <date>22 September 2008</date>
	/// <summary>
	/// Interaction logic for OpenGames.xaml
	/// </summary>
	public partial class OpenGames : Window
	{
		#region Declarations
		/// <summary>
		/// The create game dialog.
		/// </summary>
		protected CreateGame createDialog;
		#endregion

		#region Properties

		#region Joined
		/// <summary>
		/// Was a game joined.
		/// </summary>
		protected bool Joined { get; set; }
		#endregion

		#region Game
		private Engine.Game _game;
		/// <summary>
		/// The Game Engine object.
		/// </summary>
		public Engine.Game Game 
		{
			get
			{
				return this._game;
			}

			set
			{
				this._game = value;
				this.Game.OpenGameReceived += new Wormhole.Engine.Communication.OpenGameReceivedDelegate(Game_OpenGameReceived);
				this.Game.GameClosed += new Wormhole.Engine.Communication.GameClosedDelegate(Game_GameClosed);
				this.Game.JoinResponse += new Wormhole.Engine.Communication.JoinResponseDelegate(Game_JoinResponse);
			}
		}
		#endregion

		#region Open Games
		/// <summary>
		/// A list of open games.
		/// </summary>
		protected ObservableCollection<Wormhole.Engine.Communication.Game> openGames;
		#endregion

		#endregion

		#region Constructor
		/// <summary>
		/// Initialize a default instance of the class.
		/// </summary>
		public OpenGames()
		{
			InitializeComponent();
			this.openGames = new ObservableCollection<Wormhole.Engine.Communication.Game>();
			this.lstGames.ItemsSource = this.openGames;
		}
		#endregion

		#region Event Handlers

		#region Create Click
		/// <summary>
		/// Create Click
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void btnCreate_Click(object sender, RoutedEventArgs e)
		{
			this.DisplayCreateGameDialog();
		}
		#endregion

		#region Open Game Received
		/// <summary>
		/// Handle an open game that was received.
		/// </summary>
		/// <param name="game"></param>
		void Game_OpenGameReceived(Wormhole.Engine.Communication.Game game)
		{
			// need the invoke to handle the cross thread calling
			this.Dispatcher.Invoke(
				DispatcherPriority.Normal,
				(System.Windows.Forms.MethodInvoker)delegate() {
					this.AddOpenGame(game);
			});
		}
		#endregion

		#region Game Closed
		/// <summary>
		/// Handle a game that was closed.
		/// </summary>
		/// <param name="game">The closed game.</param>
		void Game_GameClosed(Wormhole.Engine.Communication.Game game)
		{
			this.Dispatcher.Invoke(
				DispatcherPriority.Normal,
				(System.Windows.Forms.MethodInvoker)delegate() {
					this.CloseGame(game);
			});
		}
		#endregion

		#region Selection Changed
		/// <summary>
		/// Handle the event when the game selection chages.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void lstGames_SelectionChanged(object sender, SelectionChangedEventArgs e)
		{
			// get the selected game
			Communication.Game selected = this.lstGames.SelectedValue as Communication.Game;

			// set the join button state
			this.btnJoin.IsEnabled = (selected != null);
		}
		#endregion

		#region Join Click
		/// <summary>
		/// Handle the join event.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void btnJoin_Click(object sender, RoutedEventArgs e)
		{
			// get the selected game
			Communication.Game selected = this.lstGames.SelectedValue as Communication.Game;

			// join the game
			if (selected != null)
				this.JoinGame(selected);
		}
		#endregion

		#region Join Response
		/// <summary>
		/// Handle the Join Response.
		/// </summary>
		/// <param name="game"></param>
		/// <param name="accepted"></param>
		/// <param name="message"></param>
		private void Game_JoinResponse(Wormhole.Engine.Communication.Game game, bool accepted, string message)
		{
			this.Dispatcher.Invoke(
				DispatcherPriority.Normal,
				(System.Windows.Forms.MethodInvoker)delegate() {
					this.HandleJoinResponse(game, accepted, message);
				});
		}
		#endregion

		#endregion

		#region Display Create Game Dialog
		/// <summary>
		/// Display the create game dialog.
		/// </summary>
		private void DisplayCreateGameDialog()
		{
			// display the dialog
			this.Hide();

			// create the dialog
			this.createDialog = new CreateGame();
			this.createDialog.Game = this.Game;
			this.createDialog.Owner = this.Owner;
			this.createDialog.Joined = false;
			this.createDialog.ShowDialog();

			// display the dialog open game dialog again if no game was created
			if (createDialog.Joined)
				this.Close();
			else
				this.ShowDialog();
		}
		#endregion

		#region Add Open Game
		/// <summary>
		/// Add an open game that was received to the list.
		/// </summary>
		/// <param name="game">The game that was received.</param>
		private void AddOpenGame(Wormhole.Engine.Communication.Game game)
		{
			this.openGames.Add(game);
		}
		#endregion

		#region Find Game
		/// <summary>
		/// Find a game by ID.
		/// </summary>
		/// <param name="gameID">The game ID.</param>
		/// <returns>Returns the game or null if it was not found.</returns>
		protected Wormhole.Engine.Communication.Game FindGame(Guid gameID)
		{
			foreach (Wormhole.Engine.Communication.Game game in this.openGames)
			{
				if (game.ID == gameID)
					return game;
			}

			return null;
		}
		#endregion

		#region Close Game
		/// <summary>
		/// Remove a game from the list.
		/// </summary>
		/// <param name="game">The game to remove.</param>
		private void CloseGame(Wormhole.Engine.Communication.Game game)
		{
			Wormhole.Engine.Communication.Game openGame = this.FindGame(game.ID);
			if (openGame != null)
			{
				this.openGames.Remove(openGame);
			}
		}
		#endregion

		#region Join Game
		/// <summary>
		/// Attempt to join the game.
		/// </summary>
		/// <param name="game">The game to join.</param>
		protected void JoinGame(Communication.Game game)
		{
			this.Game.JoinGame(game);
		}
		#endregion

		#region Handle Join Response
		/// <summary>
		/// Handle the game join response.
		/// </summary>
		/// <param name="game"></param>
		/// <param name="accepted"></param>
		/// <param name="message"></param>
		private void HandleJoinResponse(Wormhole.Engine.Communication.Game game, bool accepted, string message)
		{
			if (accepted)
			{
				this.Joined = true;
				this.Close();
			}
			else
			{
				this.Joined = false;
				MessageBox.Show(this, message, "Could Not Join", MessageBoxButton.OK, MessageBoxImage.Error);
			}
		}
		#endregion
	}
}
